package com.basker.pisces.core.jdbc;

import java.math.BigDecimal;
import java.sql.JDBCType;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.util.Assert;

import com.basker.pisces.exception.ExceptionFactory;

/**
 * 管理java类型与{@link JDBCType}的映射
 *
 * <p>
 * 映射规则如下：
 * <li>{@link Byte}：{@link JDBCType#TINYINT}
 * <li>{@link Short}：{@link JDBCType#SMALLINT}
 * <li>{@link Integer}：{@link JDBCType#INTEGER}
 * <li>{@link Long}：{@link JDBCType#BIGINT}
 * <li>{@link Float}：{@link JDBCType#FLOAT}
 * <li>{@link Double}：{@link JDBCType#DOUBLE}
 * <li>{@link BigDecimal}：{@link JDBCType#DECIMAL}
 * <li>{@link Boolean}：{@link JDBCType#BOOLEAN}
 * <li>{@link Character}：{@link JDBCType#CHAR}
 * <li>{@link String}：{@link JDBCType#VARCHAR}
 * <li>{@link Date}：{@link JDBCType#TIMESTAMP}
 * <li>{@link Timestamp}：{@link JDBCType#TIMESTAMP}
 * <li>{@link Byte[]}：{@link JDBCType#BINARY}
 * <li>枚举：{@link JDBCType#INTEGER}
 *
 * @author hangwen
 */
public class JdbcTypeMapper {
    private static final Map<Class<?>, JDBCType> SQLT_YPES;

    static {
        SQLT_YPES = new HashMap<Class<?>, JDBCType>();

        SQLT_YPES.put(Byte.class, JDBCType.TINYINT);
        SQLT_YPES.put(byte.class, JDBCType.TINYINT);

        SQLT_YPES.put(Short.class, JDBCType.SMALLINT);
        SQLT_YPES.put(short.class, JDBCType.SMALLINT);

        SQLT_YPES.put(Integer.class, JDBCType.INTEGER);
        SQLT_YPES.put(int.class, JDBCType.INTEGER);

        SQLT_YPES.put(Long.class, JDBCType.BIGINT);
        SQLT_YPES.put(long.class, JDBCType.BIGINT);

        SQLT_YPES.put(Float.class, JDBCType.FLOAT);
        SQLT_YPES.put(float.class, JDBCType.FLOAT);

        SQLT_YPES.put(Double.class, JDBCType.DOUBLE);
        SQLT_YPES.put(double.class, JDBCType.DOUBLE);

        SQLT_YPES.put(BigDecimal.class, JDBCType.DECIMAL);

        SQLT_YPES.put(Boolean.class, JDBCType.BOOLEAN);
        SQLT_YPES.put(boolean.class, JDBCType.BOOLEAN);

        SQLT_YPES.put(Character.class, JDBCType.CHAR);
        SQLT_YPES.put(char.class, JDBCType.CHAR);

        SQLT_YPES.put(String.class, JDBCType.VARCHAR);

        SQLT_YPES.put(Date.class, JDBCType.TIMESTAMP);
        SQLT_YPES.put(Timestamp.class, JDBCType.TIMESTAMP);

        SQLT_YPES.put(Byte[].class, JDBCType.BINARY);
        SQLT_YPES.put(byte[].class, JDBCType.BINARY);
    }

    /**
     * 获取指定java类型映射的JDBCType,找不到会抛出异常
     *
     * @param javaClass
     * @return
     */
    public static JDBCType getJDBCType(Class<?> javaClass) {
        Assert.notNull(javaClass, "parameter 'javaClass' is required");

        if (javaClass.isEnum()) {
            return JDBCType.INTEGER;
        }

        JDBCType jdbcType = SQLT_YPES.get(javaClass);

        if (jdbcType == null) {
            if (Collection.class.isAssignableFrom(javaClass)) {
                return JDBCType.VARCHAR;
            }

            if (Object.class.equals(javaClass)) {
                return JDBCType.VARCHAR;
            }

            throw ExceptionFactory.createRuntimeException("pisces-core.JDBCTypeMapper.getJDBCType-001",
                    javaClass.getName());
        }

        return jdbcType;
    }
}
